package com.cctc.rds.raft.core.rpc.election;

import com.cctc.rds.raft.core.util.IdUtils;

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Raft 竞选 [投票] 调度器。
 */
public class ElectionRpcScheduler implements Runnable {
    public interface ElectionFunction {
        void startElection();
    }

    private ElectionFunction electionFunction;
    private long electionMs;
    private Thread scheduler;
    private final AtomicLong lastTime = new AtomicLong(System.currentTimeMillis());
    private boolean stop = false;

    public ElectionRpcScheduler(ElectionFunction electionFunction, long electionMs) {
        this.electionFunction = electionFunction;
        this.electionMs = electionMs;
        this.scheduler = new Thread(this, "elect-rpc-scheduler-" + IdUtils.newId());
        this.scheduler.setDaemon(true);
    }

    public void start() {
        scheduler.start();
    }

    @Override
    public void run() {
        while (!stop) {
            if (System.currentTimeMillis() - lastTime.get() >= electionMs) {
                callElectionFunction();
            }
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException ignored) {
            }
        }
    }

    private void callElectionFunction() {
        try {
            electionFunction.startElection();
        } catch (Throwable ignored) {
        } finally {
            reset();
        }
    }

    public void reset() {
        lastTime.set(System.currentTimeMillis());
    }

    public void stop() {
        stop = true;
        lastTime.set(Integer.MAX_VALUE);
    }

}
